package com.itheima.appserver.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.itheima.appserver.interceptor.UserThreadLocal;
import com.itheima.commons.constants.Constants;
import com.itheima.commons.pojo.mongo.Publish;
import com.itheima.commons.pojo.mongo.Video;
import com.itheima.dubbo.interfaces.PublishApi;
import com.itheima.dubbo.interfaces.VideoApi;
import org.bson.types.ObjectId;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.commons.pojo.mongo.Comment;
import com.itheima.commons.pojo.domain.UserInfo;
import com.itheima.commons.vo.reception.CommentVo;
import com.itheima.commons.vo.reception.PageResult;
import com.itheima.dubbo.interfaces.CommentApi;
import com.itheima.dubbo.interfaces.UserInfoApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author yaohu
 * @date 2021/12/9
 * @Version 1.0
 * @describe
 */
@Service
public class CommentsService {

    @Reference
    private CommentApi commentApi;

    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private PublishApi publishApi;

    @Reference
    private VideoApi videoApi;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 创建评论对象
     *
     * @param publishId   圈子ID/评论ID
     * @param content     评论内容
     * @param commentType 评论类型 点赞 => 1 评论 => 2 喜欢 => 3
     * @return
     */
    private Comment createComment(String publishId, String content, Integer commentType) {
        Comment comment = new Comment();
        // 评论ID
        comment.setId(new ObjectId());
        // 圈子ID/评论ID
        comment.setPublishId(new ObjectId(publishId));
        // 评论类型
        comment.setCommentType(commentType);
        // 评论内容
        comment.setContent(content);
        // 评论人ID
        comment.setUserId(UserThreadLocal.getUserId());
        // 发布圈子/评论人ID
        // 优秀的app都会传这个值 但它没有 要自己查
        Publish publish = publishApi.queryPublishById(publishId);
        // 说明当前传递过来的publishId不是圈子的ID
        if (ObjectUtil.isNotNull(publish)) {
            comment.setPublishUserId(publish.getUserId());
        } else {
            // publishId有可能是评论表中的ID 也有可能是 小视频中的ID
            // 根据这个publishId去查询评论表
            Comment commentId = commentApi.queryCommentById(publishId);
            if (ObjectUtil.isNotNull(commentId)){
                comment.setPublishUserId(commentId.getUserId());
            }else {
                Video video = videoApi.queryVideoById(publishId);
                comment.setPublishUserId(video.getUserId());
            }
        }

        // 评论树
        comment.setIsParent(false);
        // 父级ID
        comment.setParentId(null);
        // 评论时间
        comment.setCreated(System.currentTimeMillis());
        return comment;
    }

    /**
     * 评论点赞
     *
     * @param publishId 圈子ID
     * @return
     */
    public Long likeComment(String publishId) {
        Comment comment = createComment(publishId, null, 1);
        Long likeCount = commentApi.likeComment(comment);

        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, likeCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId(), "1");
        return likeCount;
    }

    /**
     * 取消评论点赞
     *
     * @param publishId
     * @return
     */
    public Long disLikeComment(String publishId) {
        Long disLikeCount = commentApi.disLikeComment(UserThreadLocal.getUserId(), publishId);
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, disLikeCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
        return disLikeCount;
    }

    /**
     * 发表评论
     *
     * @param publishId
     * @param content
     */
    public void saveComments(String publishId, String content) {
        Comment comment = createComment(publishId, content, 2);
        Long commentCount = commentApi.saveComment(comment);
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_COMMENT_HASHKEY, commentCount.toString());
    }

    /**
     * 喜欢
     *
     * @param publishId
     * @return
     */
    public Long loveComment(String publishId) {
        Comment comment = createComment(publishId, null, 3);
        Long loveCount = commentApi.loveComment(comment);
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LOVE_HASHKEY, loveCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId(), "1");

        return loveCount;
    }

    /**
     * 取消喜欢
     *
     * @param publishId
     * @return
     */
    public Long unLoveComment(String publishId) {
        Long unLoveCount = commentApi.disLoveComment(UserThreadLocal.getUserId(), publishId);
        // 把当前这个圈子的点赞数给保存到redis中
        redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_LIKE_HASHKEY, unLoveCount.toString());
        // 把自己对这个圈子点赞的标记存储到redis中
        redisTemplate.opsForHash().delete(Constants.MOVEMENTS_INTERACT_KEY + publishId, Constants.MOVEMENT_ISLOVE_HASHKEY + UserThreadLocal.getUserId());
        return unLoveCount;
    }

    /**
     * 分页查询评论列表
     *
     * @param publishId
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult queryCommentList(String publishId, Integer page, Integer pageSize) {

        PageResult pageResult = commentApi.queryCommentList(publishId, page, pageSize);
        // 如果没有评论 返回空集合
        if (CollUtil.isEmpty(pageResult.getItems())) {
            return pageResult;
        }
        // 如果有评论 获取每条评论的评论人userId
        List<Long> userIds = CollUtil.getFieldValues(pageResult.getItems(), "userId", Long.class);
        // 根据userId，查询对应的用户信息userInfo
        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(userIds);

        List<CommentVo> voList = new ArrayList<>();
        for (Object item : pageResult.getItems()) {
            Comment comment = (Comment) item;
            // 拼接VO对象
            CommentVo commentVo = new CommentVo();
            // 评论的id
            commentVo.setId(comment.getId().toHexString());
            // 评论信息
            commentVo.setContent(comment.getContent());
            // 评论时间
            commentVo.setCreateDate(DateUtil.format(new Date(comment.getCreated()), "HH:mm"));

            UserInfo userInfo = userInfoMap.get(comment.getUserId());
            // 评论人头像
            commentVo.setAvatar(userInfo.getLogo());
            // 评论人昵称
            commentVo.setNickname(userInfo.getNickName());

            // 评论的点赞数量
            Long likeCount = Convert.toLong(redisTemplate.opsForHash().get(Constants.MOVEMENTS_INTERACT_KEY + comment.getId(), Constants.MOVEMENT_LIKE_HASHKEY));
            // 说明当前这个圈子没有人点赞 或者有人点赞但是Redis中没值
            if (ObjectUtil.isNull(likeCount)) {
                // 从MongoDB中进行查询
                likeCount = commentApi.queryLikeCount(comment.getId().toHexString());
                // 把查询到数据给保存到Redis中
                redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + comment.getId(), Constants.MOVEMENT_LIKE_HASHKEY, likeCount.toString());
            }
            commentVo.setLikeCount(Convert.toInt(likeCount));

            // 是否点赞
            Boolean isLike = redisTemplate.opsForHash().hasKey(Constants.MOVEMENTS_INTERACT_KEY, Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId());
            if (!isLike) {
                // 从MongoDB中进行查询
                isLike = commentApi.queryUserIsLike(UserThreadLocal.getUserId(), comment.getId().toHexString());
                if (isLike) {
                    // 把查询到数据给保存到Redis中
                    redisTemplate.opsForHash().put(Constants.MOVEMENTS_INTERACT_KEY + comment.getId(), Constants.MOVEMENT_ISLIKE_HASHKEY + UserThreadLocal.getUserId(), "1");
                }
            }
            // 当前登录用户是否对该评论点赞
            commentVo.setHasLiked(isLike ? 1 : 0);

            voList.add(commentVo);
        }
        pageResult.setItems(voList);
        return pageResult;
    }
}
